﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;

namespace LaserAutoTest.Common
{
    /// <summary>
    ///  TCPServer类 服务端程序
    /// </summary>
    public class SocketTcpServer
    {
        public bool IsConnected { get; private set; } = false;
        public bool IsStartListener { get; private set; } = false;
        private object obj = new object();
        public PushSockets pushSockets;

        /// <summary>
        /// 信号量
        /// </summary>
        private Semaphore semap = new Semaphore(5, 5000);

        /// <summary>
        /// 客户端列表集合
        /// </summary>
        public List<SocketBase> ClientList = new List<SocketBase>();

        /// <summary>
        /// 服务端实例对象
        /// </summary>
        public TcpListener Listener;

        /// <summary>
        /// 当前的ip地址
        /// </summary>
        private IPAddress IpAddress;

        /// <summary>
        /// 初始化消息
        /// </summary>
        private const string InitMsg = "TCP服务端";

        /// <summary>
        /// 监听的端口
        /// </summary>
        private int Port;

        /// <summary>
        /// 当前ip和端口节点对象
        /// </summary>
        private IPEndPoint Ip;

        /// <summary>
        /// 初始化服务器对象
        /// </summary>
        /// <param name="ipAddress">IP地址</param>
        /// <param name="port">端口号</param>
        public void InitSocket(IPAddress ipAddress, int port)
        {
            this.IpAddress = ipAddress;
            this.Port = port;
            this.Listener = new TcpListener(ipAddress, port);
        }

        /// <summary>
        /// 初始化服务器对象
        /// </summary>
        /// <param name="ipAddress"></param>
        /// <param name="port"></param>
        public void InitSocket(string ipAddress, int port)
        {
            this.IpAddress = IPAddress.Parse(ipAddress);
            this.Port = port;
            this.Ip = new IPEndPoint(this.IpAddress, port);
            this.Listener = new TcpListener(this.IpAddress, port);
        }

        /// <summary>
        /// 服务端启动监听，处理链接
        /// </summary>
        public void Start()
        {
            try
            {
                Listener.Start();
                IsConnected = true;
                IsStartListener = true;
                Thread Accth = new Thread(new ThreadStart(
                    delegate
                    {
                        while (true)
                        {
                            if (!IsConnected)
                            {
                                break;
                            }
                            GetAcceptTcpClient();
                            Thread.Sleep(100);
                        }
                    }
                ));
                Accth.Start();
            }
            catch (SocketException ex)
            {
                SocketBase sks = new SocketBase();
                sks.Ex = ex;
                pushSockets.Invoke(sks);
                //throw ex;
            }
        }

        /// <summary>
        /// 获取处理新的链接请求
        /// </summary>
        private void GetAcceptTcpClient()
        {
            try
            {
                if (Listener.Pending())
                {
                    semap.WaitOne();
                    //接收到挂起的客户端请求链接
                    TcpClient tcpClient = Listener.AcceptTcpClient();
                    //tcpClient.ReceiveTimeout = 10;
                    tcpClient.Client.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 5000, 1000), null);//设置Keep-Alive参数20221130增加
                    //维护处理客户端队列
                    Socket socket = tcpClient.Client;
                    NetworkStream stream = new NetworkStream(socket, true);
                    SocketBase sks = new SocketBase(tcpClient.Client.RemoteEndPoint as IPEndPoint, tcpClient, stream);
                    sks.NewClientFlag = true;
                    //推送新的客户端连接信息
                    pushSockets.Invoke(sks);
                    //加入客户端队列
                    AddClientList(sks);
                    //客户端异步接收数据
                    sks.NetStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
                    //链接成功后主动向客户端发送一条消息
                    //if(stream.CanWrite)
                    //{
                    //    byte[] buffer = Encoding.UTF8.GetBytes(this.InitMsg);
                    //    stream.Write(buffer, 0, buffer.Length);
                    //}
                    semap.Release();
                }
            }
            catch (Exception ex)
            {
                //throw ex;
            }
        }

        /// <summary>
        /// KeepAlive函数参数说明20221130增加:
        /// </summary>
        /// <param onOff="ir"></param>是否开启KeepAlive
        /// <param keepAliveTime="ir"></param>网络畅通时KeepAlive的时间间隔
        /// <param keepAliveInterval="ir"></param>网络不通时KeepAlive的时间间隔
        private byte[] KeepAlive(int onOff, int keepAliveTime, int keepAliveInterval)
        {
            byte[] buffer = new byte[12];
            BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
            BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
            BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
            return buffer;
        }

        /// <summary>
        /// 异步接收发送的的信息
        /// </summary>
        /// <param name="ir"></param>
        private void EndReader(IAsyncResult ir)
        {
            SocketBase sks = ir.AsyncState as SocketBase;
            if (sks != null && Listener != null)
            {
                try
                {
                    if (sks.NewClientFlag || sks.Offset != 0)
                    {
                        sks.NewClientFlag = false;
                        sks.Offset = sks.NetStream.EndRead(ir);
                        //推送到UI
                        pushSockets.Invoke(sks);
                        sks.NetStream.BeginRead(sks.RecBuffer, 0, sks.RecBuffer.Length, new AsyncCallback(EndReader), sks);
                    }
                }
                catch (Exception skex)
                {
                    lock (obj)
                    {
                        ClientList.Remove(sks);
                        SocketBase sk = sks;
                        //标记客户端退出程序
                        sk.ClientDispose = true;
                        sk.Ex = skex;
                        if(pushSockets!=null)
                        {
                            //推送至UI
                            pushSockets.Invoke(sks);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 客户端加入队列
        /// </summary>
        /// <param name="sk"></param>
        private void AddClientList(SocketBase sk)
        {
            lock (obj)
            {
                SocketBase socketBase = ClientList.Find(o => o.Ip == sk.Ip);
                if (socketBase == null)
                {
                    ClientList.Add(sk);
                }
                else
                {
                    ClientList.Remove(socketBase);
                    ClientList.Add(sk);
                }
            }
        }

        /// <summary>
        /// 服务端停止监听
        /// </summary>
        public void Stop()
        {
            if (Listener != null)
            {
                //《=====20221130增加
                for (int i = 0; i < ClientList.Count; i++)
                {
                    ClientList[i].Client.Close();
                    ClientList[i].Client.Dispose();
                    Thread.Sleep(10);
                }
                //========================》
                Listener.Stop();
                Listener = null;
                IsStartListener = false;
                IsConnected = false;
                pushSockets = null;
            }
        }

        /// <summary>
        /// 向所有在线客户端发送消息
        /// </summary>
        /// <param name="SendData">消息内容</param>
        public void SendToAll(string SendData)
        {
            //for (int i = 0; i < ClientList.Count; i++)
            //{
            //    SendToClient(ClientList[i].Ip, SendData);
            //}
        }

        /// <summary>
        /// 向单独的一个客户端发送消息
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="SendData"></param>
        public void SendToClient(IPEndPoint ip, string SendData)
        {
            try
            {
                SocketBase sks = ClientList.FirstOrDefault(t => t.Ip.ToString() == ip.ToString());
                if (sks == null)
                {
                    return;
                }
                else if (!sks.Client.Connected)
                {
                    //标识客户端下线
                    sks.ClientDispose = true;
                    sks.Ex = new Exception("客户端没有连接");
                    pushSockets.Invoke(sks);
                }
                if (sks.Client.Connected)
                {
                    List<byte> PackedData = new List<byte>();
                    byte[] buffer;
                    NetworkStream nStream = sks.NetStream;
                    //nStream.WriteTimeout = 10;
                    if (nStream.CanWrite)
                    {

                        PackedData.AddRange(Encoding.UTF8.GetBytes(SendData));//长度
                        PackedData.Add(0x0D);
                        PackedData.Add(0x0A);
                        buffer = PackedData.ToArray();
                        nStream.Write(buffer, 0, buffer.Length);

                    }
                    else
                    {
                        //避免流被关闭,重新从对象中获取流
                        nStream = sks.Client.GetStream();
                        if (nStream.CanWrite)
                        {
                            PackedData.AddRange(Encoding.UTF8.GetBytes(SendData));//长度
                            PackedData.Add(0x0D);
                            PackedData.Add(0x0A);
                            buffer = PackedData.ToArray();
                            nStream.Write(buffer, 0, buffer.Length);
                        }
                        else
                        {
                            //如果还是无法写入,那么认为客户端中断连接.
                            ClientList.Remove(sks);
                            SocketBase ks = new SocketBase();
                            sks.ClientDispose = true;//如果出现异常,标识客户端下线
                            sks.Ex = new Exception("客户端无连接");
                            pushSockets.Invoke(sks);//推送至UI
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                SocketBase sks = new SocketBase();
                sks.ClientDispose = true;//如果出现异常,标识客户端退出
                sks.Ex = ex;
                pushSockets.Invoke(sks);//推送至UI
                //throw ex;
            }
        }

        public void SendToClientRedLight(IPEndPoint ip, string command)
        {
            try
            {
                SocketBase sks = ClientList.FirstOrDefault(t => t.Ip.ToString() == ip.ToString());
                if (sks == null)
                {
                    return;
                }
                else if (!sks.Client.Connected)
                {
                    //标识客户端下线
                    sks.ClientDispose = true;
                    sks.Ex = new Exception("客户端没有连接");
                    pushSockets.Invoke(sks);
                }

                if (sks.Client.Connected)
                {
                    List<byte> PackedData = new List<byte>();
                    byte[] buffer = new byte[6];
                    NetworkStream nStream = sks.NetStream;

                    if (command == "POW")
                    {
                        buffer[0] = 0xAA;
                        buffer[1] = 0x55;
                        buffer[2] = 0x02;
                        buffer[3] = 0xFE;
                        buffer[4] = 0x01;
                        buffer[5] = 0x00;
                    }
                    else if (command == "Digit")
                    {
                        buffer[0] = 0xAA;
                        buffer[1] = 0x55;
                        buffer[2] = 0x02;
                        buffer[3] = 0xEF;
                        buffer[4] = 0x00;
                        buffer[5] = 0xF1;
                    }
                    else
                    {
                        PackedData.AddRange(Encoding.UTF8.GetBytes(command));//长度
                        PackedData.Add(0x0D);
                        PackedData.Add(0x0A);
                        buffer = PackedData.ToArray();
                    }
                    if (nStream.CanWrite)
                    {
                        nStream.Write(buffer, 0, buffer.Length);
                    }
                    else
                    {
                        //避免流被关闭,重新从对象中获取流
                        nStream = sks.Client.GetStream();
                        if (nStream.CanWrite)
                        {
                            nStream.Write(buffer, 0, buffer.Length);
                        }
                        else
                        {
                            //如果还是无法写入,那么认为客户端中断连接.
                            ClientList.Remove(sks);
                            SocketBase ks = new SocketBase();
                            sks.ClientDispose = true;//如果出现异常,标识客户端下线
                            sks.Ex = new Exception("客户端无连接");
                            pushSockets.Invoke(sks);//推送至UI
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                SocketBase sks = new SocketBase();
                sks.ClientDispose = true;//如果出现异常,标识客户端退出
                sks.Ex = ex;
                pushSockets.Invoke(sks);//推送至UI
                //throw ex;
            }
        }
    }
}